package system

import (
	"context"
	"net/http"
	"reflect"
	"slices"
	"strconv"

	"portal/internal/errorx"
	"portal/internal/svc"
	"portal/internal/tool/auth"
	"portal/internal/types"
	"portal/model"
	"portal/tools/excel"

	"github.com/xuri/excelize/v2"
	"github.com/zeromicro/go-zero/core/logx"
)

type ExportUserLogic struct {
	logx.Logger
	ctx    context.Context
	svcCtx *svc.ServiceContext
	menuModel model.SysMenuModel
	userModel model.SysUserModel
	deptModel model.SysDeptModel
}

func NewExportUserLogic(ctx context.Context, svcCtx *svc.ServiceContext) *ExportUserLogic {
	return &ExportUserLogic{
		Logger: logx.WithContext(ctx),
		ctx:    ctx,
		svcCtx: svcCtx,
		menuModel: model.NewSysMenuModel(svcCtx.Orm),
		userModel: model.NewSysUserModel(svcCtx.Orm),
		deptModel: model.NewSysDeptModel(svcCtx.Orm),
	}
}

func (l *ExportUserLogic) ExportUser(req *types.ListUserRequest,w http.ResponseWriter) error {
	err := auth.HasPermission(l.menuModel, l.ctx, "system:user:list")
	if err != nil {
		return errorx.Unauthorized
	}
	authinfo, err := auth.GetAuth(l.ctx)
	if err != nil {
		return errorx.AuthNoFound
	}
	roles, _ := auth.GetRoles(l.ctx)
	deptId, err := strconv.Atoi(authinfo.DeptId)
	if err != nil {
		return errorx.TypeTransError
	}
	transDeptId := int64(deptId)
	deptIds := make([]*int64, 0)
	isAdmin,_ := auth.IsAdmin(l.ctx)
	if len(req.DeptId) > 0 {
		if isAdmin {
			deptIds = append(deptIds, &transDeptId)
		}else {
			depts, err := getDepts(l.ctx, int64(deptId), roles, l.deptModel, &types.ListDeptRequest{})
			if err != nil {
				return errorx.Unauthorized
			}
			if len(req.DeptId) > 0 {
				isHas := slices.ContainsFunc(depts, func(d *types.Dept) bool {
					return d.DeptId == transDeptId
				})
				if !isHas {
					return errorx.AuthNoFound
				}
				deptIds = append(deptIds, &transDeptId)
			} else {
				for _, val := range depts {
					deptIds = append(deptIds, &val.DeptId)
				}
			}
		}
	}
	userdtos, err := l.userModel.ListByCondition(l.ctx, nil, req, deptIds, isAdmin)
	if err != nil {
		return errorx.NewBizError(500, err.Error())
	}
	uservos := make([]*types.User, 0)
	for _, user := range userdtos {
		uservos = append(uservos, &types.User{
			UserId:      user.UserId,
			DeptId:      strconv.Itoa(int(user.DeptId.Int64)),
			UserName:    user.UserName,
			NickName:    user.NickName,
			UserType:    user.UserType,
			Avatar:      user.Avatar,
			Email:       user.Email,
			Phonenumber: user.Phonenumber,
			Sex:         user.Sex,
			Status:      user.Status,
			LoginDate:   user.LoginDate,
			UpdateTime:  user.UpdateTime,
			CreateTime:  user.CreateTime,
		})
	}
	file := excelize.NewFile()
	defer file.Close()
	tagMap := excel.InitTag2FieldIdx(types.User{},"xlsx_export")
	rowData := tableColumnsToRow(uservos,tagMap)
	for idx,row := range *rowData {
		cell,err := excelize.CoordinatesToCellName(1,idx + 1)
		if err != nil {
			return errorx.FileParseError
		}
		file.SetSheetRow("Sheet1",cell,&row)
	}
	// 设置Content-Type
	w.Header().Set("Content-Type", "application/octet-stream")
	// 设置Content-Disposition
	w.Header().Set("Content-Disposition", "attachment; filename=user.xlsx")
	// var file os.File
	_,err = file.WriteTo(w)

	// 写入文件内容到ResponseWriter
	// _, err := io.Copy(rw)
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
	}
	return nil
}

// 将 行数据 按照反射的方式转为结构体 TableColumn
func tableColumnsToRow(data []*types.User, tag2fieldIndex map[string]int) *[][]interface{} {
	row := make([][]interface{},0)
	header := make([]interface{},0)
	propIdxs := make([]int,0)
	for key,value := range tag2fieldIndex {
		header = append(header, key)
		propIdxs = append(propIdxs, value)
	}
	row = append(row, header)
	for _,firstval := range data {
		body := make([]interface{},0)
		uv := reflect.ValueOf(firstval)
		uv = uv.Elem()
		for _,propIdx := range propIdxs {
			val := uv.Field(propIdx).Interface()
			body = append(body, val)
		} 
		row = append(row, body)
	}
	return &row
}
